﻿using System;
using System.ComponentModel;
using UnityConfiguration.Converters;
using mpu = Microsoft.Practices.Unity;
using mpuu = Microsoft.Practices.Unity.Utility;
using UnityConfiguration.Infrastructure;

namespace UnityConfiguration
{
    /// <summary>
    /// Class that gives a value for an instance.
    /// It lets you specify the type, value, and type converter to
    /// use to create the instance.
    /// </summary>
    public class InstanceValue : InjectionParameterValue
    {
        private string _TypeName;
        private string _Value;
        private string _TypeConverterName;

        /// <summary>
        /// Returns the string name of the type of the represented object.
        /// </summary>
        public string TypeName {
            get { return _TypeName; }
            set { _TypeName = value; }
        }

        /// <summary>
        /// Optional value used when creating the represented object.
        /// </summary>
        public string Value {
            get { return _Value; }
            set { _Value = value; }
        }

        /// <summary>
        /// Type name of the type converter used to create the represented object..
        /// If not specified, the default type converter (if any) is used.
        /// </summary>
        public string TypeConverterName {
            get { return _TypeConverterName; }
            set { _TypeConverterName = value; }
        }

        /// <summary>
        /// Create an instance as specified by this element's configuration.
        /// </summary>
        /// <returns>The created instance</returns>
        public object CreateInstance() {
            if (TypeToCreate == typeof(string)) {
                return Value;
            }

            TypeConverter converter = GetTypeConverter(TypeToCreate, TypeConverterName, TypeResolver);
            return converter.ConvertFromString(Value);
        }

        private static TypeConverter GetTypeConverter(
            Type typeToCreate,
            string typeConverterName,
            UnityTypeResolver typeResolver) {
            if (!string.IsNullOrEmpty(typeConverterName)) {
                // return the type converter override
                Type converterType = typeResolver.ResolveType(typeConverterName);
                return (TypeConverter)Activator.CreateInstance(converterType);
            } else {
                // return the default type converter
                // missing TypeDescriptor so use the default
                return new DefaultTypeConverter(typeToCreate);
            }
        }

        /// <summary>
        /// Return an instance of <see cref="InjectionParameterValue"/> based
        /// on the contents of this 
        /// </summary>
        /// <param name="targetType">Type of parent parameter. Ignored by this implementation.</param>
        /// <returns>The created InjectionParameterValue, ready to pass to the container config API.</returns>
        public override mpu.InjectionParameterValue CreateParameterValue(Type targetType) {
            Type typeToCreate;
            if (string.IsNullOrEmpty(TypeName)) {
                typeToCreate = targetType;
            } else {
                typeToCreate = TypeResolver.ResolveType(TypeName);
            }
            return new mpu.InjectionParameter(typeToCreate, CreateInstance());
        }

        /// <summary>
        /// The <see cref="Type"/> instance after resolution of type aliases.
        /// </summary>
        /// <remarks>If <see cref="TypeName"/> property is empty, this returns typeof(string).</remarks>
        public Type TypeToCreate {
            get { return TypeResolver.ResolveWithDefault(TypeName, typeof(string)); }
        }
    }
}
